﻿#region Copyright
// Please do not remove this section. If you can improve it further, you may send a copy to the
// author at azharkhan@hotmail.com 
// 
// Author : Azhar A. Khan
// Date : 08/27/2008
// Filename : HWGridView.cs
// History : 
//            08/27/2008 Initial Version
//            08/28/2008 Romoved  ApplyFilterCommand call from OnFilterCommand, since it will be called in OnPreRender
#endregion

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Entersoft.Web.UI.WebControls
{
    [ToolboxData("<{0}:GridView runat=server></{0}:GridView>")]
    public sealed class GridView : System.Web.UI.WebControls.GridView
    {
        DropDownList m_ddlPageNo;
        readonly Hashtable m_txtFilter = new Hashtable();
        readonly Hashtable m_ddlFilter = new Hashtable();

        private static readonly object EventFilterCommand = new object();
        private const double EPSILON = 0.0;

        #region Propiedades
        [Category("Extend GridView Events")]
        public List<Object> Buttons { get; set; }

        [Category("Extend GridView Events")]
        public String ParentHeaderCssClass { get; set; }

        [Category("Extend GridView Events"), DefaultValue("")]
        public String ButtonsHeaderCssClass { get; set; }

        [Category("Extend GridView Events"), DefaultValue("GridView Title")]
        public String GridTitle { get; set; }

        [Category("Extend GridView Events"), DefaultValue("No")]
        public bool ShowGridTitle { get; set; }

        [Category("Extend GridView Events"), DefaultValue("Left")]
        public HorizontalAlign GridTitleAlign { get; set; }

        [Category("Extend GridView Events"), Description("ExtededGridView_OnFilterCommand")]
        public event EventHandler FilterCommand
        {
            add
            {
                Events.AddHandler(EventFilterCommand, value);
            }
            remove
            {
                Events.RemoveHandler(EventFilterCommand, value);
            }
        }
        #endregion 

        #region Constructor
        public GridView()
        {
            PagerSettings.Position = PagerPosition.TopAndBottom;
        }
        #endregion

        #region Pager

        private void InitializeTopPager(GridViewRow row, int columnSpan)
        {
            if (GridTitle == String.Empty && Buttons == null) return;

            var tableTemp = new Table();
            var rowTemp = new TableRow();

            tableTemp.Width = new Unit("100%");
            tableTemp.CssClass = ParentHeaderCssClass;

            var cellTemp = new TableCell
                                     {
                                         Text = GridTitle ?? "&nbsp;",
                                         HorizontalAlign = GridTitleAlign,
                                         VerticalAlign = VerticalAlign.Middle,
                                         Width = new Unit("60%")
                                     };

            rowTemp.Controls.AddAt(0, cellTemp);

            cellTemp = new TableCell
                           {
                               CssClass = ButtonsHeaderCssClass,
                               VerticalAlign = VerticalAlign.Middle,
                               HorizontalAlign = HorizontalAlign.Right,
                               Width = new Unit("40%")
                           };

            if (Buttons != null)
            {
                var t1 = new Table();
                var tr1 = new TableRow();
                var tc1 = new TableCell
                              {
                                  VerticalAlign = VerticalAlign.Middle,
                                  HorizontalAlign = HorizontalAlign.Right
                              };

                foreach (var objeto in Buttons)
                {
                    if (objeto is ImageButton)
                        tc1.Controls.Add((ImageButton) objeto);
                    else if (objeto is Button)
                        tc1.Controls.Add((Button) objeto);
                }

                tr1.Controls.Add(tc1);
                t1.Controls.Add(tr1);

                cellTemp.Controls.Add(t1);

                rowTemp.Controls.Add(cellTemp);
            }

            tableTemp.Controls.AddAt(0, rowTemp);

            var cell = new TableCell();
            
            if (columnSpan > 1)
                cell.ColumnSpan = columnSpan;

            cell.Controls.Add(tableTemp);
            row.Cells.Add(cell);
        }

        private void InitializeBottomPager(GridViewRow row, int columnSpan, PagedDataSource pagedDataSource)
        {
            var goToCell = new TableCell();
            goToCell.Style.Add(HtmlTextWriterStyle.Width, "100%");

            var pagerTable = (Table)row.Cells[0].Controls[0];
            pagerTable.Rows[0].Cells.Add(goToCell);

            var ltrlSpanBegin = new Literal {Text = "<span style='float:right'>Page&nbsp;"};

            if (m_ddlPageNo == null)
            {
                m_ddlPageNo = new DropDownList {Width = new Unit("50px")};
                m_ddlPageNo.Font.Size = new FontUnit("10px");
                m_ddlPageNo.CssClass = PagerStyle.CssClass;
                //m_ddlPageNo.Style.Add("height", "10px");
                m_ddlPageNo.AutoPostBack = false;

                for(int I = 1;I<=PageCount;I++)
                {
                    m_ddlPageNo.Items.Add(new ListItem(I.ToString(), I.ToString()));
                }
            }

            var ltrlText = new Literal {Text = "&nbsp;>&nbsp;"};

            var btnGo = new Button
                               {
                                   Text = "Go",
                                   CommandName = "Page1",
                                   CommandArgument = "2",
                                   ID = "ctl_PageIndex",
                                   Height = new Unit("16px")
                               };

            btnGo.Font.Size = new FontUnit("10px");
            btnGo.CssClass = PagerStyle.CssClass;

            btnGo.Style.Add(HtmlTextWriterStyle.Color, PagerStyle.ForeColor.ToString());

            var ltrlSpanEnd = new Literal {Text = "</span>"};

            goToCell.Controls.Add(ltrlSpanBegin);
            goToCell.Controls.Add(m_ddlPageNo);
            goToCell.Controls.Add(ltrlText);
            goToCell.Controls.Add(btnGo);
            goToCell.Controls.Add(ltrlSpanEnd);
        }

        protected override void InitializePager(GridViewRow row,
                                                int columnSpan,
                                                PagedDataSource pagedDataSource)
        {
            if (Controls[0].Controls.Count == 0 &&
               (PagerSettings.Position == PagerPosition.Top ||
                PagerSettings.Position == PagerPosition.TopAndBottom))
            {
                InitializeTopPager(row, columnSpan);
            }
            else
            {
                base.InitializePager(row, columnSpan, pagedDataSource);
                InitializeBottomPager(row, columnSpan, pagedDataSource);
            }
        }

        private void HandlePageCommand(GridViewCommandEventArgs e)
        {
            var ddlPageIndex = (DropDownList)((Control)e.CommandSource).Parent.Controls[1];
            var btnPageIndex = (Button)((Control)e.CommandSource).Parent.Controls[3];

            if (ddlPageIndex.Text.Length <= 0) return;

            try
            {
                int ndx = int.Parse(ddlPageIndex.Text);
                ndx = ndx - 1;
                if (ndx >= PageCount)
                    ndx = PageCount - 1;
                if (ndx < 0)
                    ndx = 0;
                PageIndex = ndx;
                btnPageIndex.CommandArgument = ddlPageIndex.Text;
            }
            catch (Exception e1)
            {
                if (e1.Message.Length == 0)
                    return;
            }
        }

        protected override void OnRowCommand(GridViewCommandEventArgs e)
        {
            switch (e.CommandName)
            {
                case "Page1":
                    HandlePageCommand(e);
                    break;
                default:
                    base.OnRowCommand(e);
                    break;
            }
        }
        #endregion

        #region Filter

        private void AddFilter(int columnIndex,
            TableCell headerCell,
            DataControlField field)
        {
            if (headerCell.Controls.Count == 0)
            {
                var ltlHeaderText = new LiteralControl(headerCell.Text);
                headerCell.Controls.Add(ltlHeaderText);
            }

            var ltlBreak = new LiteralControl("</br>");

            headerCell.Controls.Add(ltlBreak);

            TextBox txtFilter;

            if (m_txtFilter.Contains(columnIndex))
                txtFilter = (TextBox)m_txtFilter[columnIndex];
            else
            {
                txtFilter = new TextBox {ID = ID + "_txtFilter" + columnIndex.ToString()};

                // +headerCell.ClientID;
                if (Math.Abs(field.ItemStyle.Width.Value - 0.0) > EPSILON)
                {
                    txtFilter.Style.Add(HtmlTextWriterStyle.Width, Convert.ToString(field.ItemStyle.Width.Value - 40) + "px");
                }
                else if (Math.Abs(field.HeaderStyle.Width.Value - Convert.ToDouble("0.0")) > EPSILON)
                {
                    txtFilter.Style.Add(HtmlTextWriterStyle.Width, Convert.ToString(field.HeaderStyle.Width.Value - 40) + "px");
                }
                txtFilter.Style.Add(HtmlTextWriterStyle.Height, "10px");
                txtFilter.Style.Add(HtmlTextWriterStyle.FontSize, "9px");
                m_txtFilter[columnIndex] = txtFilter;
            }

            DropDownList ddlFilter;
            if (m_ddlFilter.Contains(columnIndex))
                ddlFilter = (DropDownList)m_ddlFilter[columnIndex];
            else
            {
                ddlFilter = new DropDownList {ID = ID + "_ddlFilter" + columnIndex.ToString()};

                ddlFilter.Items.Add(" ");
                ddlFilter.Items.Add("=");
                ddlFilter.Items.Add("<");
                ddlFilter.Items.Add(">");
                ddlFilter.Items.Add("<=");
                ddlFilter.Items.Add(">=");
                ddlFilter.AutoPostBack = true;
                ddlFilter.SelectedIndexChanged += HandleFilterCommand;
                //ddlFilter.SelectedIndex = 0;
                ddlFilter.Style.Add(HtmlTextWriterStyle.Width, "30px");
                ddlFilter.Height = new Unit("7px");
                ddlFilter.Style.Add(HtmlTextWriterStyle.Height, "8px");
                ddlFilter.Style.Add(HtmlTextWriterStyle.FontSize, "8px");
                m_ddlFilter[columnIndex] = ddlFilter;
            }

            headerCell.Controls.Add(txtFilter);
            headerCell.Controls.Add(ddlFilter);
        }

        private void AddFilters(GridViewRow headerRow,
            DataControlField[] fields)
        {
            for (int i = 0; i < Columns.Count; i++)
            {
                if (Columns[i].HeaderText.EndsWith(" "))
                {
                    AddFilter(i, headerRow.Cells[i], fields[i]);
                }
            }
        }

        private void AddGlyph(System.Web.UI.WebControls.GridView grid, GridViewRow item)
        {
            var glyph = new Label {EnableTheming = false};
            glyph.Font.Name = "webdings";
            glyph.Text = (grid.SortDirection == SortDirection.Ascending ? " 5" : " 6");
            //glyph.Font.Size = FontUnit.Medium;
            //glyph.Text = "&nbsp;" + (grid.SortDirection == SortDirection.Ascending ? "&#9650;" : "&#9660;");
            // Find the column you sorted by
            for (int i = 0; i < grid.Columns.Count; i++)
            {
                string colExpr = grid.Columns[i].SortExpression;
                if (colExpr != "" && colExpr == grid.SortExpression)
                {
                    item.Cells[i].Controls.Add(glyph);
                }
            }
        }

        private void InitializeHeaderRow(GridViewRow row, DataControlField[] fields)
        {
            AddGlyph(this, row);
            AddFilters(row, fields);
        }

        protected override void InitializeRow(GridViewRow row, DataControlField[] fields)
        {
            base.InitializeRow(row, fields);
            if (row.RowType == DataControlRowType.Header)
            {
                InitializeHeaderRow(row, fields);
            }
        }

        private String GetFilterCommand()
        {
            String filterCommand = "";
            for (int i = 0; i < Columns.Count; i++)
            {
                if (Columns[i].HeaderText.EndsWith(" "))
                {
                    //var headerCell = (DataControlFieldHeaderCell)HeaderRow.Cells[i];
                    var txtFilter = (TextBox)m_txtFilter[i];
                    var ddlFilter = (DropDownList)m_ddlFilter[i];
                    
                    if (!(Columns[i] is BoundField) || String.IsNullOrEmpty(ddlFilter.SelectedValue.Trim()))
                        continue;

                    var aColumn = (BoundField)Columns[i];

                    if (String.IsNullOrEmpty(txtFilter.Text))
                        continue;
                    
                    if (String.IsNullOrEmpty(filterCommand))
                        filterCommand = aColumn.DataField + " " + ddlFilter.SelectedValue + " " + txtFilter.Text;
                    else
                        filterCommand += " AND " + aColumn.DataField + " " + ddlFilter.SelectedValue + " " + txtFilter.Text;
                }
            }

            return filterCommand;
        }

        private void ApplyFilterCommand(String filterCommand)
        {
            var dsv = GetData();

            if (!(dsv is SqlDataSourceView)) return;

            var selectCommand = ((SqlDataSourceView)dsv).SelectCommand;

            if (selectCommand.Contains(filterCommand))
                return;

            if (selectCommand.Contains("WHERE"))
                selectCommand += " AND " + filterCommand;
            else
                selectCommand += " WHERE " + filterCommand;

            ((SqlDataSourceView)dsv).SelectCommand = selectCommand;
        }

        private void OnFilterCommand(EventArgs e)
        {
            var handler = (EventHandler)Events[EventFilterCommand];

            if (handler != null)
                handler(this, e);
        }

        private void HandleFilterCommand(object sender, EventArgs e)
        {
            RequiresDataBinding = true;  //this is required to make sure that unsetting of filter is also handled

            var filterArgs = new FilterCommandEventArgs {FilterExpression = GetFilterCommand()};

            OnFilterCommand(filterArgs);
        }

        protected override void OnPreRender(EventArgs e)
        {
            var filterCommand = GetFilterCommand();

            if (String.IsNullOrEmpty(filterCommand) == false)
                ApplyFilterCommand(filterCommand);

            base.OnPreRender(e);
        }
        #endregion
    }
}
